/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable @typescript-eslint/no-explicit-any */
import { defineComponent, h, PropType, ref, resolveComponent } from 'vue';
import { useControlController, useNamespace } from '@ibiz-template/vue3-util';
import {
  IControl,
  IDETBRawItem,
  ISysCalendar,
  IDETBGroupItem,
  IDEToolbarItem,
  ISysCalendarItem,
  IDETBUIActionItem,
} from '@ibiz/model-core';
import {
  IModal,
  IButtonState,
  ScriptFactory,
  IControlProvider,
  IButtonContainerState,
  IOverlayPopoverContainer,
} from '@ibiz-template/runtime';
import { MenuItem } from '@imengyu/vue3-context-menu';
import dayjs from 'dayjs';
import { ResourceScheduleTableController } from './resource-schedule-table.controller';
import { IGlobalConfig } from './resource-scheduler';
import { CodelistColorSetting } from './codelist-color-setting/codelist-color-setting';
import { setting } from './resource-scheduler/components/schedule-toolbar/svg-icon';
import './resource-schedule-table.scss';

export const ResourceScheduleTable = defineComponent({
  name: 'IBizResourceScheduleTable',
  props: {
    /**
     * @description 模型数据
     */
    modelData: { type: Object as PropType<IControl>, required: true },
    /**
     * @description 应用上下文对象
     */
    context: { type: Object as PropType<IContext>, required: true },
    /**
     * @description 视图参数对象
     * @default {}
     */
    params: { type: Object as PropType<IParams>, default: () => ({}) },
    /**
     * @description 部件适配器
     */
    provider: { type: Object as PropType<IControlProvider> },
    /**
     * @description 是否为缓存模式
     */
    isCacheMode: { type: Boolean, default: false },
  },
  setup() {
    const c = useControlController(
      (...args) => new ResourceScheduleTableController(...args),
    );
    const ns = useNamespace('resource-schedule-table');
    const scheduleTable = ref(null);

    // *上下文菜单相关 /

    let ContextMenu: IData;

    const iBizRawItem = resolveComponent('IBizRawItem');
    const iBizIcon = resolveComponent('IBizIcon');

    /**
     * @description 计算注入属性
     * @param {(ISysCalendar | ISysCalendarItem)} model
     * @param {IData} data
     * @returns {*}
     */
    const calcAttrs = (model: ISysCalendar | ISysCalendarItem, data: IData) => {
      const attrs: IParams = {};
      model.controlAttributes?.forEach(item => {
        if (item.attrName && item.attrValue)
          attrs[item.attrName] = ScriptFactory.execSingleLine(item.attrValue, {
            ...c.getEventArgs(),
            data,
          });
      });
      return attrs;
    };

    c.evt.on('onMounted', () => {
      // 有上下文菜单时加载组件
      if (Object.values(c.contextMenus).length > 0) {
        const importMenu = () => import('@imengyu/vue3-context-menu');
        importMenu().then(value => {
          ContextMenu = value.default;
          if (ContextMenu.default && !ContextMenu.showContextMenu) {
            ContextMenu = ContextMenu.default;
          }
        });
      }
    });

    c._evt.on('updateTableLineHeight', (event: IData) => {
      const { data } = event;
      if (scheduleTable.value) {
        (scheduleTable.value as IData).onConfigRefresh(data[0]);
      }
    });

    /**
     * 计算上下文菜单组件配置项集合
     */
    const calcContextMenuItems = (
      toolbarItems: IDEToolbarItem[],
      calendarData: any,
      evt: MouseEvent,
      menuState: IButtonContainerState,
    ): MenuItem[] => {
      const result: MenuItem[] = [];
      toolbarItems.forEach(item => {
        if (item.itemType === 'SEPERATOR') {
          result.push({
            divided: 'self',
          });
          return;
        }

        const buttonState = menuState[item.id!] as IButtonState;
        if (buttonState && !buttonState.visible) {
          return;
        }

        // 除分隔符之外的公共部分
        let menuItem: MenuItem | undefined = {};
        if (item.showCaption && item.caption) {
          menuItem.label = item.caption;
        }
        if (item.sysImage && item.showIcon) {
          menuItem.icon = (<iBizIcon icon={item.sysImage}></iBizIcon>) as any;
        }

        // 界面行为项
        if (item.itemType === 'DEUIACTION') {
          menuItem.disabled = buttonState.disabled;
          menuItem.clickClose = true;
          const { uiactionId } = item as IDETBUIActionItem;
          if (uiactionId) {
            menuItem.onClick = () => {
              c.doUIAction(uiactionId, calendarData, evt, item.appId);
            };
          }
        } else if (item.itemType === 'RAWITEM') {
          const { rawItem } = item as IDETBRawItem;
          if (rawItem) {
            menuItem.label = (
              <iBizRawItem rawItem={item as IDETBRawItem}></iBizRawItem>
            ) as any;
          }
        } else if (item.itemType === 'ITEMS') {
          // 分组项绘制子菜单
          const group = item as IDETBGroupItem;
          if (group.detoolbarItems?.length) {
            menuItem.children = calcContextMenuItems(
              group.detoolbarItems!,
              calendarData,
              evt,
              menuState,
            );
          }
          // 分组项配置界面行为组
          if (group.uiactionGroup && group.groupExtractMode) {
            const menuItems = group.uiactionGroup.uiactionGroupDetails
              ?.filter(detail => {
                const detailState: IButtonState = menuState[detail.id!];
                return detailState.visible;
              })
              .map(detail => {
                const detailState: IButtonState = menuState[detail.id!];
                const { sysImage } = detail as IData;
                return {
                  label: detail.showCaption ? detail.caption : undefined,
                  icon: detail.showIcon ? (
                    <iBizIcon icon={sysImage}></iBizIcon>
                  ) : undefined,
                  disabled: detailState.disabled,
                  clickableWhenHasChildren: true,
                  onClick: () => {
                    ContextMenu.closeContextMenu();
                    c.doUIAction(
                      detail.uiactionId!,
                      calendarData,
                      evt,
                      detail.appId,
                    );
                  },
                };
              });
            switch (group.groupExtractMode) {
              case 'ITEMS':
                menuItem.children = menuItems as any;
                break;
              case 'ITEMX':
                if (menuItems) {
                  menuItem = menuItems[0] as any;
                  if (menuItem) {
                    menuItem.children = menuItems.slice(1) as any;
                  }
                }
                break;
              case 'ITEM':
              default:
                menuItem = undefined;
                if (menuItems) {
                  result.push(...(menuItems as any));
                }
                break;
            }
          }
        }
        if (menuItem) {
          result.push(menuItem);
        }
      });

      return result;
    };

    /**
     * 右键菜单事件
     */
    const onNodeContextmenu = async (
      type: string,
      item: any,
      evt: MouseEvent,
    ) => {
      console.log('右键菜单点击事件------', type, item, evt);
      // 阻止原生浏览器右键菜单打开
      evt.preventDefault();
      evt.stopPropagation();
      let targetToolbar: IData;
      let contextMenuC: IData;
      if (type === 'cell') {
        const { controls = [] } = c.model;
        const quickToolbar = controls.find(
          (x: any) => x.name === `${c.model.name!}_quicktoolbar`,
        );
        if (!quickToolbar) {
          return;
        }
        targetToolbar = quickToolbar;
        contextMenuC = c.contextMenus[quickToolbar.id!];
      } else {
        const { sysCalendarItems } = c.model;
        const targetCalendarItem = sysCalendarItems?.find(
          (_item: ISysCalendarItem) => {
            return _item.id === type;
          },
        );
        if (!targetCalendarItem?.decontextMenu) {
          return;
        }
        targetToolbar = targetCalendarItem.decontextMenu;
        contextMenuC = c.contextMenus[targetCalendarItem.id!];
      }

      if (!contextMenuC || !contextMenuC.model.detoolbarItems) {
        return;
      }

      // 更新菜单的权限状态
      await contextMenuC.calcButtonState(item, targetToolbar.appDataEntityId, {
        view: c.view,
        ctrl: c,
      });
      const menuState = contextMenuC.state.buttonsState;

      const menus: MenuItem[] = calcContextMenuItems(
        contextMenuC.model.detoolbarItems,
        item,
        evt,
        menuState as IButtonContainerState,
      );
      if (!menus.length) {
        return;
      }

      ContextMenu.showContextMenu({
        x: evt.x,
        y: evt.y,
        customClass: ns.b('context-menu'),
        items: menus,
        zIndex: 9999,
      });
    };

    /**
     * 点击事件
     */
    const onBodyClick = async (
      type: 'resource' | 'task' | 'cell',
      config: IGlobalConfig,
      data: IScheduleResource | IScheduleTask | IData,
      event: MouseEvent,
    ) => {
      if (type === 'task') {
        c.onTaskClick(data);
      } else {
        c.onResetNavView();
      }
      console.log('点击事件------', type, config, data, event);
    };

    /**
     * 计算任务时间
     *
     * @param {IScheduleTask} data
     * @return {*}
     */
    const calcTaskTime = (data: IScheduleTask) => {
      const { start, end } = data;
      return `${dayjs(start).format('YYYY-MM-DD HH:mm')} - ${dayjs(end).format(
        'YYYY-MM-DD HH:mm',
      )}`;
    };

    // * 颜色设置相关 /
    let settingOverlay: IOverlayPopoverContainer | void;

    /**
     * 处理颜色设置
     */
    const handleColorSetting = async (_evt: MouseEvent) => {
      if (settingOverlay) {
        settingOverlay.dismiss();
        settingOverlay = undefined;
        return;
      }
      // 打开弹框
      settingOverlay = ibiz.overlay.createModal(
        (modal: IModal) =>
          h(CodelistColorSetting, {
            modal,
            taskColorOptions: c.state.taskColorOptions,
            codeListItems: c.codeListItems,
          }),
        undefined,
        {
          title: '颜色设置',
          modalClass: ns.b('color-setting-modal'),
          width: 700,
          height: 650,
        } as IData,
      );
      settingOverlay?.present(_evt.currentTarget as HTMLElement);
      // 弹框关闭
      const result: IData = await settingOverlay.onWillDismiss();
      const taskColorOptions = result?.data[0] as IData;
      if (taskColorOptions) {
        c.setTaskColorOptions(taskColorOptions);
        // 持久化存储
        c.saveConfig();
      }
    };

    return {
      c,
      ns,
      scheduleTable,
      calcAttrs,
      onBodyClick,
      calcTaskTime,
      onNodeContextmenu,
      handleColorSetting,
    };
  },
  render() {
    return (
      <div class={this.ns.b()}>
        <schedule-table
          ref='scheduleTable'
          resources={this.c.state.resources}
          tasks={this.c.state.tasks}
          startTime={this.c.startTime}
          endTime={this.c.endTime}
          caption={this.c.state.caption}
          onDataRefresh={this.c.refresh.bind(this.c)}
          onSave={this.c.onSave.bind(this.c)}
          onSaveAs={this.c.onSaveAs.bind(this.c)}
          onConfigChange={this.c.handleConfigChange.bind(this.c)}
          onContextMenu={(
            type: 'resource' | 'task' | 'cell',
            config: IGlobalConfig,
            data: IScheduleResource | IScheduleTask | IData,
            event: MouseEvent,
          ) => this.onNodeContextmenu(type, data, event)}
          onBodyClick={(
            type: 'resource' | 'task' | 'cell',
            config: IGlobalConfig,
            data: IScheduleResource | IScheduleTask | IData,
            event: MouseEvent,
          ) => this.onBodyClick(type, config, data, event)}
          beforeResourceDrop={this.c.beforeResourceDrop.bind(this.c)}
          resourceDropCompleted={this.c.resourceDropCompleted.bind(this.c)}
          beforeTaskDrop={this.c.beforeTaskDrop.bind(this.c)}
          taskDropCompleted={this.c.taskDropCompleted.bind(this.c)}
          beforeTaskUpdate={this.c.beforeTaskUpdate.bind(this.c)}
          taskUpdateCompleted={this.c.taskUpdateCompleted.bind(this.c)}
          taskColorOptions={this.c.state.taskColorOptions}
          taskTypeField={this.c.taskTypeField}
          {...this.calcAttrs(this.c.model, {
            resources: this.c.state.resources,
            tasks: this.c.state.tasks,
          })}
        >
          {{
            extraToolbar: () => {
              return [
                this.c.codeListItems && (
                  <div
                    class={[
                      this.ns.b('extra-toolbar-item'),
                      'schedule-toolbar-item',
                      'is-btn',
                    ]}
                    title='颜色设置'
                    onClick={_evt => this.handleColorSetting(_evt)}
                  >
                    <span v-html={setting}></span>
                  </div>
                ),
              ];
            },
            resourceItem: (data: IScheduleResource) => {
              const scriptCode = this.c.calcHasRender('resource');
              if (scriptCode) {
                const html = this.c.getCustomHtml(scriptCode, data);
                return <div class='resource-item-content' v-html={html}></div>;
              }
              return <div class='resource-item-content'>{data.name}</div>;
            },
            taskItem: (data: IScheduleTask) => {
              const scriptCode = this.c.calcHasRender('task');
              if (scriptCode) {
                const html = this.c.getCustomHtml(scriptCode, data);
                return (
                  <div class='task-item-content-content' v-html={html}></div>
                );
              }
              return (
                <el-popover placement='right-start' width='300'>
                  {{
                    reference: () => {
                      return (
                        <div class='task-item-content-content'>
                          {data.name || ''}
                        </div>
                      );
                    },
                    default: () => {
                      if (data.start.getFullYear() === data.end.getFullYear())
                        return (
                          <div>
                            <div>{this.calcTaskTime(data)}</div>
                            <div>[任务] {data.name}</div>
                          </div>
                        );
                    },
                  }}
                </el-popover>
              );
            },
          }}
        </schedule-table>
      </div>
    );
  },
});
